;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
;程序名称:NameTelREC.asm
;功能:人名/电话简单记录表
;环境:16BIT DOS实模式(windows/dos或dosbox)
;编译器:MASM 5.1-6X 
;用法:看说明
;返回值:没有
;破坏寄存器:不适用
;
;这是贴吧上一个问题，什么也没有，只有一幅加重肩颈炎病情的图。
;http://tieba.baidu.com/p/3829872119 
;题目要求建立一个只有９个人名／电话资料的资料纪录，包括输入和查询功能，列出全部/刪除记录是我手痒加的。
;题目有普通性，代码示范了查询和表列的技术，并不复杂。
;加了簡單的解釋，若不明白，debug一下就是。
;
;注意:这只是一个范例程式，具备最起码的功能，没有太花巧的技术。
;若你需要其他功能或加入或删减任何代码，请随便，但不能要求作者为你订制特定的功能或
;根据功课要求而改变这个子程序改变那个子程序，若是代码错误或优化代码的意见，
;则欢迎提出:)
;
;
    max_name equ 20
	max_tel equ 12
	max_serial equ 2
	max_record equ 9
	max_rows equ 5
	Menu_x equ 22
	Menu_y equ 1
	Bar_L equ 19
	up_key equ 48h
	down_key equ 50h
	enter_key equ 0dh
	ESC_key equ 1bh

Data segment 
	inputName_str db 0dh,0ah,09,09,'INPUT NAME:$'
	inputTel_str db 0dh,0ah,09,09,'INPUT TELEPHONE NUMBER:$'
	inputSerial_str db 0dh,0ah,09,09,09,'INPUT SERIAL:$'
	inputDel_str db 0dh,0ah,09,09,09,'Input Delete Serial:$'
	no_num_str db 0dh,0ah,09,09,09,'NO THIS NUMBER'
	pause_str db 0dh,0ah,09,09,09,'Hit a key to continue....$'
	y_n_str db 0dh,0ah,09,09,09,'Delete this record ? (y/n)$'
	delete_add dw 0
	full_str db 0dh,0ah,09,09,09,'Data Full$'
Menu_str label byte
	;db 09,09,09,' - RECORD MENU -',0dh,0ah,09,09,09
	db ' - RECORD MENU -',0dh,0ah,09,09,09
	db '1. Input Record',0dh,0ah,09,09,09
	db '2. Query Record',0dh,0ah,09,09,09
	db '3. Delete Record',0dh,0ah,09,09,09
	db '4. List Record',0dh,0ah,09,09,09
	db '5. Exit',0dh,0ah,09,09,09
	db 18h,19h,' to Choose & <Enter>$'
sub_table label byte
	dw offset INRECORD
	dw offset PRINT
	dw offset Del_REC
	dw offset LIST_REC
	dw offset QUIT
	input_buffer db 20,0,20 dup (0)
	Xrecord_L equ (max_serial + max_name + max_tel)
	Xrecord db Xrecord_L * max_record dup (0),0,0 ;end of record 
disp_title label byte
	db 0dh,0ah,09,09, Xrecord_L + 2 dup  ('-')
	db 0dh,0ah,09,09,'No.',20h,'Name',max_name - 4 dup (20h),20h,20h,'Tel.',0dh,0ah,'$'
	disp_record_str db 09,09
	disp_record db (Xrecord_L + 10) dup (20h),0dh,0ah,'$'
	menu_pointer dw 0
Data Ends

STACK SEGMENT STACK
	DB 100H DUP(?)
STACK ENDS

code segment
assume ds:data,cs:code,SS:STACK
begin:
	mov ax,data
	mov ds,ax
	mov es,ax
	cld
displayMenu:
	call cls
	mov dl,Menu_x + 2
	mov dh,Menu_y - 1
	call SetCur
	mov dx,offset Menu_str ;print menu
	mov ah,9
	int 21h
	mov menu_pointer,0
	mov cx,3030h
	call SetCurSz ;close cursor
redraw:
	call draw_arrow
rekey:
	mov ax,0c07h ;Clear Buffer and Invoke Keyboard Function
	int 21h
	or al,al
	jz rekey5  ;returns 0 for extended keystroke
	cmp al,Esc_key
	jnz rekey2
	call quit
rekey2:
	cmp al,enter_key
	jz choose_Ok
	mov ah,al
	sub ah,'0'
	cmp ah,1
	jb rekey
	cmp ah,max_rows
	ja rekey
	mov bl,ah
	dec bl
	mov bh,0
	mov menu_pointer,bx
	call draw_arrow
	jmp short choose_ok
rekey5:
	mov ah,7 ;read extended keystroke
	int 21h 
	cmp al,up_key
	jnz rekey10
	cmp menu_pointer,0
	jz rekey
	dec menu_pointer
	jmp short redraw
rekey10:
	cmp al,down_key
	jnz rekey
	cmp menu_pointer,max_rows - 1
	jae rekey
	inc menu_pointer
	jmp short redraw
choose_Ok:
	mov cx,0c0dh
	call SetCurSz ;open cursor
	mov dh,menu_y + max_rows
	mov dl,0
	call SetCur 
	mov bx,menu_pointer
	shl bx,1
	add bx,offset sub_table ;point to sub-menu offset
	call [bx]
	jmp displayMenu
;-------------
INRECORD:
	mov si,offset Xrecord
	mov cx,1 ;serial no.   ;first record
inR_10:
	mov ax,[si]  ;get record no.
	cmp ax,0  ;is it empty ?
	jz inR_20 ;yes
	add si,Xrecord_L ;try next record buffer 
	inc cx ; next
	cmp cx,max_record ; is it full ?
	jbe inR_10 ; no 
	call print_full  
	call pause_proc  ;print pause
	ret ;leave
inR_20:
	mov [si],cx  ;save record no.
inR_30:
	call INNAME  ;get name input
	mov cl,input_buffer + 1 ;get input length
	mov ch,0  ; clear
	jcxz inR_30 ;no input
	mov di,si ;save name
	add di,2 ;by pass record no.
	mov si,offset input_buffer + 2  ;source 
	push di ;--------save
	rep movsb ;move name to my record
	mov al,0  ;make zero
	stosb
inR_40:
	call INTELE ;get tel no.
	mov cl,input_buffer + 1
	mov ch,0
	jcxz inR_40
	pop di ;---------restore
	add di,max_name
	mov si,offset input_buffer + 2
	rep movsb ;save tel no. to my record
	mov al,0 ;make zero
	stosb
	ret
;-------------
print_full:  
	mov dx,offset full_str
	mov ah,9
	int 21h
	ret
;-------------
INNAME:
	mov ah,9
	mov dx,offset inputName_str
	int 21h
	mov input_buffer,max_name - 1
	mov input_buffer + 1,0
	mov ah,10  ;get input
	mov dx,offset input_buffer
	int 21h
	ret
;-------------
INTELE:
	mov ah,9
	mov dx,offset inputTel_str
	int 21h
	mov input_buffer,max_tel - 1
	mov input_buffer + 1,0
	mov ah,10 ;get input
	mov dx,offset input_buffer
	int 21h
	ret
;-------------
Del_REC:
	mov ah,9
	mov dx,offset inputDel_str
	int 21h
	call Get_key
	jnc DelR10 
	ret
DelR10:
	mov ah,0  ;clear 
	call get_record  ;search record
	jnc DelR20
	jmp print20 ; no such record  
DelR20:
	call print_record  ;print record
	mov dx,offset y_n_str
	mov ah,9
	int 21h
DelR30:
	mov ah,7  ;wait a key
	int 21h
	cmp al,1bh ;ESC
	jz DelR35
	and al,11011111b ;upcase
	cmp al,'Y'
	jnz DelR40
	int 29h
	mov si,delete_add
	mov word ptr [si],0 ;clear record
DelR35:
	ret
DelR40:
	cmp al,'N'
	jnz DelR30
	int 29h
ret
;-------------
PRINT:  ;query 
	mov di,offset disp_record
	mov al,20h
	mov cx,Xrecord_L + 10
	rep stosb ; clear display buffer
;
	mov ah,9
	mov dx,offset inputSerial_str
	int 21h
	mov cx,2
	call Get_key
	jnc print10
	ret
print10:
	mov ah,0  ;clear 
	call get_record  ;search record
	jnc print60  ;ok
print20:
	mov dx,offset no_num_str ;fail 
	jmp short print70
print60:
	call print_record  ;print record
pause_proc:   
	mov dx,offset pause_str
print70: 
	mov ah,9
	int 21h
	mov ah,7  ;wait a key
	int 21h
	ret
;-------------
LIST_REC:
	mov dx,offset disp_title
	mov ah,9
	int 21h
	mov bp,0  ; first record
LIST10:
	mov ax,bp  
	call get_record  ;next record 
	jc LIST15
	call print_RecordLine
LIST15:
	inc bp  ;next
	cmp bp,9 ;is it finish ?
	jbe list10 ;no
LIST20:
	call pause_proc ;with a key
listx:
	ret
;-------------
QUIT:
	call cls
	mov ah,4ch  ;quit to dos
	int 21h
;-------------
cls:
	mov ah,0fh                  ;get display mode to al
	int 10h
	mov ah,0                    ;Set display mode
	int 10h
	ret
;---------------------------------------------------------
get_record:  ;record no. in ax 0-x 
	mov bx,Xrecord_L   ;record length
	mul bx
	mov si,offset Xrecord  
	add si,ax  ;pointer to  record
	cmp word ptr [si],0  ;occupancy ? 
	jnz get_10    ;no 
	stc
	ret
get_10:
	mov delete_add,si
	mov di,offset disp_record
	lodsw	;get no.
	add al,0   ;BCD ajust
	aam  ; change ot BCD format
	or ax,3030h  ;change to ASCII
	xchg al,ah  
	stosw  ;store it
	mov ax,2020h  ;space
	stosw 
	push si
	push di
get_20:
	lodsb  ;load name record to  display buffer
	or al,al
	jz get_30
	stosb
	jmp short get_20
get_30: 
	pop di
	pop si
	add si,max_name  ;next
	add di,max_name + 2
get_40:
	lodsb  ;load tel. record to  display buffer
	or al,al
	jz get_x
	stosb
	jmp short get_40
get_x:
	clc
	ret
;-------------------------------------------------
print_record:
	mov dx,offset disp_title
	mov ah,9
	int 21h
print_RecordLine:
	mov dx,offset disp_record_str
	mov ah,9
	int 21h
	ret
;-------------------------------------------------
Get_key:
	mov ah,7 ;read key
	int 21h
	cmp al,0dh ;is it enter?
	jnz GetK10 ;no
GetK5:
	stc
	ret ;quit 
GetK10:
	cmp al,1bh ;is it ESC ?
	jz GetK5 ;no
	cmp al,'1'  ;check 0-9
	jb Get_key  ;not in range
	cmp al,'9'
	ja Get_key  ;not in range
	int 29h ;print al 
	sub al,'0'  ;ASCII change to value
	dec al    ;1-9 -> 0-8 record begin with 0
	clc
	ret
;-----------------------------------
;Menu_x equ 26
;Menu_y equ 2
;Bar_L equ 17
draw_arrow:
	mov cx,5
	mov dl,Menu_x
	mov dh,Menu_y
draw10:
	call SetCur
	mov al,20h ; ;clear arrow
	int 29h
	inc dh
	loop draw10
;
	mov cx,5
	mov dl,Menu_x +  Bar_L
	mov dh,Menu_y
draw20:
	call SetCur
	mov al,20h ;clear arrow
	int 29h
	inc dh
	loop draw20
;
	mov ax,menu_pointer
	mov dh,Menu_y
	add dh,al
	mov dl,Menu_x
	call SetCur
	mov al,'>'
	int 29h
;
	mov dl,Menu_x +  Bar_L
	call SetCur
	mov al,'<'
	int 29h
	ret
;-----------------------------------
SetCur:
	mov bh,0
	mov ah,2
	int 10h
	ret
;-----------------------------------
SetCurSz:       
	mov ah,01
	int 10h
	ret
;-----------------------------------
	code ends
	end begin